library ieee;
use ieee.std_logic_1164.all;

entity flappyBird is
	port(
		F2: in bit;
		reset: in std_logic;
		resetVideo: in std_logic;
		clk: in bit;

		led1		:	out bit_vector (6 downto 0);
		led2		:	out bit_vector (6 downto 0);	
		led3		:	out bit_vector (6 downto 0);
		
		VGA_HS, VGA_VS: OUT STD_LOGIC;
		VGA_R, VGA_G, VGA_B: out std_logic_vector(3 downto 0)
	
	);
end entity;

architecture behav of flappyBird is

	-- Constantes de posicao do passaro
	constant POSICAO_INICIAL: integer := 0;

	-- Valor da posicao do passaro
	signal posicao_atual: integer;
	signal posicao_aux: integer;
	
	-- Divisor de clock para a altura do passaro
	signal countClk: integer range 0 to 10_000_000;
	signal countClk_aux: integer range 0 to 10_000_000;
	
	-- Estados da MEF
	type estados is (parado, subindo, descendo, morto);
	signal estado_atual, proximo_estado : estados;

	signal stop : std_logic;
	signal colisao : std_logic;
	signal dead: std_logic;
	
	-- F negado
	--signal F2: bit;
	signal F: bit;
	
	signal clk25: bit;

begin
	
	divisor: process(clk)
				variable  clk_aux: bit;
			begin

				if clk = '1' then
					clk_aux := not clk_aux;
					clk25 <= clk_aux;
				end if;

			end process;
			
	debounce:	process(clk, F2)
		variable clk_count1	:	natural	:= 0;
		variable clk_count2	:	natural	:= 0;
	begin
		if clk'event and clk = '1' then
			if F2 = '1' then
				clk_count2 := 0;	
				clk_count1 := clk_count1 + 1;
				if clk_count1 = 1_000_000 then
					F <= not F2;
					clk_count1 := 0;
				end if;
			else
				clk_count1 := 0 ;
				clk_count2 := clk_count2 + 1;
				if clk_count2 = 1_000_000 then
					F <= not F2;
					clk_count2 := 0;
				end if;	
			end if;
		end if;
	end process;

	-- Parte sequencial (guarda o estado atual e a posicao atual)
	p0: process(clk25, proximo_estado, countClk_aux, posicao_aux)
	begin
	
		if clk25'event and clk25 = '1' then
			
			countClk <= countClk_aux;
			
			estado_atual <= proximo_estado;
			posicao_atual <= posicao_aux;
			
		end if;
		
	end process p0;
	
	-- Parte combinatória (modifica o valor da posicao atual e do estado atual)
	p1: process (F, estado_atual, posicao_atual, reset, countClk,colisao)
	begin
	
		case (estado_atual) is
		
			-- ESTADO INICIAL (PARADO)
			when parado =>
				
				dead <= '1';
				countClk_aux <= 0;
				posicao_aux <= POSICAO_INICIAL;
				stop <= '0';
				
				if reset = '1' then
					proximo_estado <= parado;
				elsif F = '1' then 
					proximo_estado <= subindo;
				else
					proximo_estado <= parado;
				end if;
				
			-- ESTADO SUBINDO
			when subindo =>
				
				dead <= '0';
				stop <= '1';
				countClk_aux <= countClk + 1;
				if countClk = 100_000 then
					countClk_aux <= 0;
					if posicao_atual > 235 then
						--posicao_aux <= POSICAO_INICIAL;
						posicao_aux <= posicao_atual;
						--proximo_estado <= morto;
					else
						posicao_aux <= posicao_atual + 1;
					end if;
				else
					posicao_aux <= posicao_atual;
				end if;
				
				if reset = '1' then
					proximo_estado <= parado;
					countClk_aux <= 0;
				elsif colisao = '1' then
					countClk_aux <= 0;
					proximo_estado <= morto;					
				elsif F = '0' then
					countClk_aux <= 0;
					proximo_estado <= descendo;
				else
					proximo_estado <= subindo;
					
				end if;
			
			-- ESTADO DESCENDO
			when descendo =>
				
				dead <= '0';
				stop <= '1';
				countClk_aux <= countClk + 1;
			
				if countClk = 100_000 then
					countClk_aux <= 0;
					if posicao_atual < -235 then
						--posicao_aux <= POSICAO_INICIAL;
						posicao_aux <= posicao_atual;
						--proximo_estado <= morto;
					else
						posicao_aux <= posicao_atual - 1;
					end if;
				else
					posicao_aux <= posicao_atual;
				end if;
				
				if reset = '1' then
					proximo_estado <= parado;
					countClk_aux <= 0;
				elsif colisao = '1' then
					countClk_aux <= 0;
					proximo_estado <= morto;					
				elsif F = '1' then
					countClk_aux <= 0;
					proximo_estado <= subindo;
				else
					proximo_estado <= descendo;
					
				end if;
			
			-- ESTADO MORTO
			when morto =>
				
				dead <= '1';
				stop <= '0';				
				countClk_aux <= 0;
				posicao_aux <= posicao_atual; 
				
				if reset = '1' then
					proximo_estado <= parado;
				--elsif F = '1' then 
					--proximo_estado <= parado;
				else
					proximo_estado <= morto;
				end if;
		
		end case;
	
	end process p1;

	
	passarinho: entity work.vga_raster_DE0(rtl)
				port map(
							clk => clk25, reset => resetVideo, 
							VGA_HS => VGA_HS, VGA_VS => VGA_VS, 
							VGA_R => VGA_R, VGA_G => VGA_G,VGA_B => VGA_B, 
							posicao_atual => posicao_atual,
							reset_passarinho => reset,
							parado => stop,
							colisao => colisao
				);
	
	ponto: entity work.point(point_arch)
				port map(
							clk => clk25, reset => reset,
							dead => dead,
							led1 => led1,
							led2 => led2,
							led3 => led3
				);

end architecture;